home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / tar / src / tar.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  12KB  |  527 lines

  1. /*
  2.  * A public domain tar(1) program.
  3.  * 
  4.  * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
  5.  *
  6.  * @(#)tar.c 1.34 11/6/87 Public Domain - gnu
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <sys/types.h>        /* Needed for typedefs in tar.h */
  11.  
  12. extern char     *malloc();
  13. extern char     *getenv();
  14. extern char    *strncpy();
  15. extern char    *optarg;    /* Pointer to argument */
  16. extern int    optind;        /* Global argv index from getopt */
  17.  
  18. /*
  19.  * The following causes "tar.h" to produce definitions of all the
  20.  * global variables, rather than just "extern" declarations of them.
  21.  */
  22. #define TAR_EXTERN /**/
  23. #include "tar.h"
  24.  
  25. /*
  26.  * We should use a conversion routine that does reasonable error
  27.  * checking -- atoi doesn't.  For now, punt.  FIXME.
  28.  */
  29. #define intconv    atoi
  30. extern int    getoldopt();
  31. extern void    read_and();
  32. extern void    list_archive();
  33. extern void    extract_archive();
  34. extern void    diff_archive();
  35. extern void    create_archive();
  36.  
  37. static FILE    *namef;        /* File to read names from */
  38. static char    **n_argv;    /* Argv used by name routines */
  39. static int    n_argc;    /* Argc used by name routines */
  40.                 /* They also use "optind" from getopt(). */
  41.  
  42. void    describe();
  43.  
  44. #ifdef AMIGA
  45. extern char *_TZ;        /* timezone stuff */
  46. #endif
  47.  
  48. /*
  49.  * Main routine for tar.
  50.  */
  51. main(argc, argv)
  52.     int    argc;
  53.     char    **argv;
  54. {
  55.  
  56.     /* Uncomment this message in particularly buggy versions...
  57.     fprintf(stderr,
  58.      "tar: You are running an experimental PD tar, maybe use /bin/tar.\n");
  59.      */
  60.  
  61.     tar = "tar";        /* Set program name */
  62.  
  63.     options(argc, argv);
  64.  
  65.     name_init(argc, argv);
  66.  
  67.     if (f_create) {
  68.         if (f_extract || f_list || f_diff) goto dupflags;
  69.         create_archive();
  70.     } else if (f_extract) {
  71.         if (f_list || f_diff) goto dupflags;
  72.         extr_init();
  73.         read_and(extract_archive);
  74.     } else if (f_list) {
  75.         if (f_diff) goto dupflags;
  76.         read_and(list_archive);
  77.     } else if (f_diff) {
  78.         diff_init();
  79.         read_and(diff_archive);
  80.     } else {
  81. dupflags:
  82.         fprintf (stderr,
  83. "tar: you must specify exactly one of the c, t, x, or d options\n");
  84.         describe();
  85.         exit(EX_ARGSBAD);
  86.     }
  87.     exit(0);
  88.     /* NOTREACHED */
  89. }
  90.  
  91.  
  92. /*
  93.  * Parse the options for tar.
  94.  */
  95. int
  96. options(argc, argv)
  97.     int    argc;
  98.     char    **argv;
  99. {
  100.     register int    c;        /* Option letter */
  101. #ifdef AMIGA
  102.     char *timezone;
  103. #endif
  104.  
  105.     /* Set default option values */
  106.     blocking = DEFBLOCKING;        /* From Makefile */
  107.     ar_file = getenv("TAPE");    /* From environment, or */
  108. #ifdef AMIGA
  109.     timezone = getenv("TZ");
  110.     if (timezone)
  111.     {
  112.         _TZ = malloc(strlen(timezone) + 1);    /* man page unclear about */
  113.         strcpy(_TZ, timezone);        /* whether this is needed */
  114.         free(timezone);
  115.     }
  116.     else
  117.         _TZ = "CST6CDT";
  118.     tzset();
  119. #endif
  120.     if (ar_file == 0)
  121. #ifdef AMIGA
  122.         ar_file = "ram:tarfile";    /* From Makefile */
  123. #else
  124.         ar_file = DEF_AR_FILE;    /* From Makefile */
  125. #endif
  126.     /* Parse options */
  127. #ifdef AMIGA
  128.     while ((c = getoldopt(argc, argv, "aAb:BcdDf:hiklmopRstT:vxzZ")
  129. #else
  130.     while ((c = getoldopt(argc, argv, "b:BcdDf:hiklmopRstT:vxzZ")
  131. #endif
  132.         ) != EOF) {
  133.         switch (c) {
  134.  
  135. #ifdef AMIGA
  136.         case 'a':
  137.             f_archive_set++;
  138.             break;
  139.  
  140.         case 'A':
  141.             f_archive_check++;
  142.             break;
  143. #endif
  144.  
  145.         case 'b':
  146.             blocking = intconv(optarg);
  147.             break;
  148.  
  149.         case 'B':
  150.             f_reblock++;        /* For reading 4.2BSD pipes */
  151.             break;
  152.  
  153.         case 'c':
  154.             f_create++;
  155.             break;
  156.  
  157.         case 'd':
  158.             f_diff++;        /* Find difference tape/disk */
  159.             break;
  160.  
  161.         case 'D':
  162.             f_dironly++;        /* Dump dir, not contents */
  163.             break;
  164.  
  165.         case 'f':
  166.             ar_file = optarg;
  167.             break;
  168.  
  169.         case 'h':
  170.             f_follow_links++;    /* follow symbolic links */
  171.             break;
  172.  
  173.         case 'i':
  174.             f_ignorez++;        /* Ignore zero records (eofs) */
  175.             /*
  176.              * This can't be the default, because Unix tar
  177.              * writes two records of zeros, then pads out the
  178.              * block with garbage.
  179.              */
  180.             break;
  181.  
  182.         case 'k':            /* Don't overwrite files */
  183. #ifdef NO_OPEN3
  184.             fprintf(stderr,
  185.                 "tar: can't do -k option on this system\n");
  186.             exit(EX_ARGSBAD);
  187. #else
  188.             f_keep++;
  189. #endif
  190.             break;
  191.  
  192.         case 'l':
  193.             f_local_filesys++;
  194.             break;
  195.  
  196.         case 'm':
  197.             f_modified++;
  198.             break;
  199.  
  200.         case 'o':            /* Generate old archive */
  201.             f_oldarch++;
  202.             break;
  203.  
  204.         case 'p':
  205.             f_use_protection++;
  206.             break;
  207.  
  208.         case 'R':
  209.             f_sayblock++;        /* Print block #s for debug */
  210.             break;            /* of bad tar archives */
  211.  
  212.         case 's':
  213.             f_sorted_names++;    /* Names to extr are sorted */
  214.             break;
  215.  
  216.         case 't':
  217.             f_list++;
  218.             f_verbose++;        /* "t" output == "cv" or "xv" */
  219.             break;
  220.  
  221.         case 'T':
  222.             name_file = optarg;
  223.             f_namefile++;
  224.             break;
  225.  
  226.         case 'v':
  227.             f_verbose++;
  228.             break;
  229.  
  230.         case 'x':
  231.             f_extract++;
  232.             break;
  233.  
  234.         case 'z':        /* Easy to type */
  235.         case 'Z':        /* Like the filename extension .Z */
  236.             f_compress++;
  237.             break;
  238.  
  239.         case '?':
  240.             describe();
  241.             exit(EX_ARGSBAD);
  242.  
  243.         }
  244.     }
  245.  
  246.     blocksize = blocking * RECORDSIZE;
  247. }
  248.  
  249.  
  250. /* 
  251.  * Print as much help as the user's gonna get.
  252.  *
  253.  * We have to sprinkle in the KLUDGE lines because too many compilers
  254.  * cannot handle character strings longer than about 512 bytes.  Yuk!
  255.  * In particular, MSDOS MSC 4.0 (and 5.0) and PDP-11 V7 Unix have this
  256.  * problem.
  257.  */
  258. void
  259. describe()
  260. {
  261.     /* sorry, can't #ifdef AMIGA inside string */
  262.     fputs("\
  263. tar: valid options:\n\
  264. -a    set the archived bit of each file as it's added to the archive\n\
  265. -b N    blocking factor N (block size = Nx512 bytes)\n\
  266. -B    reblock as we read (for reading 4.2BSD pipes)\n\
  267. -c    create an archive\n\
  268. -d    find differences between archive and file system\n\
  269. -D    don't dump the contents of directories, just the directory\n\
  270. ", stderr); /* KLUDGE */ fputs("\
  271. -f F    read/write archive from file or device F (or hostname:/ForD)\n\
  272. -h    don't dump symbolic links; dump the files they point to\n\
  273. -i    ignore blocks of zeros in the archive, which normally mean EOF\n\
  274. -k    keep existing files, don't overwrite them from the archive\n\
  275. -l    stay in the local file system (like dump(8)) when creating an archive\n\
  276. ", stderr); /* KLUDGE */ fputs("\
  277. -m    don't extract file modified time\n\
  278. -o    write an old V7 format archive, rather than ANSI [draft 6] format\n\
  279. -p    do extract all protection information\n\
  280. -R    dump record number within archive with each message\n\
  281. -s    list of names to extract is sorted to match the archive\n\
  282. -t    list a table of contents of an archive\n\
  283. ", stderr); /* KLUDGE */ fputs("\
  284. -T F    get names to extract or create from file F\n\
  285. -v    verbosely list what files we process\n\
  286. -x    extract files from an archive\n\
  287. -z or Z    run the archive through compress(1)\n\
  288. ", stderr);
  289. }
  290.  
  291.  
  292. /*
  293.  * Set up to gather file names for tar.
  294.  *
  295.  * They can either come from stdin or from argv.
  296.  */
  297. name_init(argc, argv)
  298.     int    argc;
  299.     char    **argv;
  300. {
  301.  
  302.     if (f_namefile) {
  303.         if (optind < argc) {
  304.             fprintf(stderr, "tar: too many args with -T option\n");
  305.             exit(EX_ARGSBAD);
  306.         }
  307.         if (!strcmp(name_file, "-")) {
  308.             namef = stdin;
  309.         } else {
  310.             namef = fopen(name_file, "r");
  311.             if (namef == NULL) {
  312.                 fprintf(stderr, "tar: ");
  313.                 perror(name_file);
  314.                 exit(EX_BADFILE);
  315.             }
  316.         }
  317.     } else {
  318.         /* Get file names from argv, after options. */
  319.         n_argc = argc;
  320.         n_argv = argv;
  321.     }
  322. }
  323.  
  324. /*
  325.  * Get the next name from argv or the name file.
  326.  *
  327.  * Result is in static storage and can't be relied upon across two calls.
  328.  */
  329. char *
  330. name_next()
  331. {
  332.     static char    buffer[NAMSIZ+2];    /* Holding pattern */
  333.     register char    *p;
  334.     register char    *q;
  335.  
  336.     if (namef == NULL) {
  337.         /* Names come from argv, after options */
  338.         if (optind < n_argc)
  339.             return n_argv[optind++];
  340.         return (char *)NULL;
  341.     }
  342.     for (;;) {
  343.         p = fgets(buffer, NAMSIZ+1 /*nl*/, namef);
  344.         if (p == NULL) return p;    /* End of file */
  345.         q = p+strlen(p)-1;        /* Find the newline */
  346.         if (q <= p) continue;        /* Ignore empty lines */
  347.         *q-- = '\0';            /* Zap the newline */
  348.         while (q > p && *q == '/')  *q-- = '\0'; /* Zap trailing /s */
  349.         return p;
  350.     }
  351.     /* NOTREACHED */
  352. }
  353.  
  354.  
  355. /*
  356.  * Close the name file, if any.
  357.  */
  358. name_close()
  359. {
  360.  
  361.     if (namef != NULL && namef != stdin) fclose(namef);
  362. }
  363.  
  364.  
  365. /*
  366.  * Gather names in a list for scanning.
  367.  * Could hash them later if we really care.
  368.  *
  369.  * If the names are already sorted to match the archive, we just
  370.  * read them one by one.  name_gather reads the first one, and it
  371.  * is called by name_match as appropriate to read the next ones.
  372.  * At EOF, the last name read is just left in the buffer.
  373.  * This option lets users of small machines extract an arbitrary
  374.  * number of files by doing "tar t" and editing down the list of files.
  375.  */
  376. name_gather()
  377. {
  378.     register char *p;
  379.     static struct name namebuf[1];    /* One-name buffer */
  380.  
  381.     if (f_sorted_names) {
  382.         p = name_next();
  383.         if (p) {
  384.             namebuf[0].length = strlen(p);
  385.             if (namebuf[0].length >= sizeof namebuf[0].name) {
  386.                 fprintf(stderr, "Argument name too long: %s\n",
  387.                     p);
  388.                 namebuf[0].length = (sizeof namebuf[0].name) - 1;
  389.             }
  390.             strncpy(namebuf[0].name, p, namebuf[0].length);
  391.             namebuf[0].name[ namebuf[0].length ] = 0;
  392.             namebuf[0].next = (struct name *)NULL;
  393.             namebuf[0].found = 0;
  394.             namelist = namebuf;
  395.             namelast = namelist;
  396.         }
  397.         return;
  398.     }
  399.  
  400.     /* Non sorted names -- read them all in */
  401.     while (NULL != (p = name_next())) {
  402.         addname(p);
  403.     }
  404. }
  405.  
  406. /*
  407.  * Add a name to the namelist.
  408.  */
  409. addname(name)
  410.     char    *name;            /* pointer to name */
  411. {
  412.     register int    i;        /* Length of string */
  413.     register struct name    *p;    /* Current struct pointer */
  414.  
  415.     i = strlen(name);
  416.     /*NOSTRICT*/
  417.     p = (struct name *)
  418.         malloc((unsigned)(i + sizeof(struct name) - NAMSIZ));
  419.     if (!p) {
  420.         fprintf(stderr,"tar: cannot allocate mem for namelist entry\n");
  421.         exit(EX_SYSTEM);
  422.     }
  423.     p->next = (struct name *)NULL;
  424.     p->length = i;
  425.     strncpy(p->name, name, i);
  426.     p->name[i] = '\0';    /* Null term */
  427.     p->found = 0;
  428.     p->regexp = 0;        /* Assume not a regular expression */
  429.     p->firstch = 1;        /* Assume first char is literal */
  430.     if (index(name, '*') || index(name, '[') || index(name, '?')) {
  431.         p->regexp = 1;    /* No, it's a regexp */
  432.         if (name[0] == '*' || name[0] == '[' || name[0] == '?')
  433.             p->firstch = 0;        /* Not even 1st char literal */
  434.     }
  435.  
  436.     if (namelast) namelast->next = p;
  437.     namelast = p;
  438.     if (!namelist) namelist = p;
  439. }
  440.  
  441.  
  442. /*
  443.  * Match a name from an archive, p, with a name from the namelist.
  444.  */
  445. name_match(p)
  446.     register char *p;
  447. {
  448.     register struct name    *nlp;
  449.     register int        len;
  450.  
  451. again:
  452.     if (0 == (nlp = namelist))    /* Empty namelist is easy */
  453.         return 1;
  454.     len = strlen(p);
  455.     for (; nlp != 0; nlp = nlp->next) {
  456.         /* If first chars don't match, quick skip */
  457.         if (nlp->firstch && nlp->name[0] != p[0])
  458.             continue;
  459.  
  460.         /* Regular expressions */
  461.         if (nlp->regexp) {
  462.             if (wildmat(p, nlp->name)) {
  463.                 nlp->found = 1;    /* Remember it matched */
  464.                 return 1;    /* We got a match */
  465.             }
  466.             continue;
  467.         }
  468.  
  469.         /* Plain Old Strings */
  470.         if (nlp->length <= len        /* Archive len >= specified */
  471.          && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  472.                         /* Full match on file/dirname */
  473.          && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
  474.         {
  475.             nlp->found = 1;        /* Remember it matched */
  476.             return 1;        /* We got a match */
  477.         }
  478.     }
  479.  
  480.     /*
  481.      * Filename from archive not found in namelist.
  482.      * If we have the whole namelist here, just return 0.
  483.      * Otherwise, read the next name in and compare it.
  484.      * If this was the last name, namelist->found will remain on.
  485.      * If not, we loop to compare the newly read name.
  486.      */
  487.     if (f_sorted_names && namelist->found) {
  488.         name_gather();        /* Read one more */
  489.         if (!namelist->found) goto again;
  490.     }
  491.     return 0;
  492. }
  493.  
  494.  
  495. /*
  496.  * Print the names of things in the namelist that were not matched.
  497.  */
  498. names_notfound()
  499. {
  500.     register struct name    *nlp;
  501.     register char        *p;
  502.  
  503.     for (nlp = namelist; nlp != 0; nlp = nlp->next) {
  504.         if (!nlp->found) {
  505.             fprintf(stderr, "tar: %s not found in archive\n",
  506.                 nlp->name);
  507.         }
  508.         /*
  509.          * We could free() the list, but the process is about
  510.          * to die anyway, so save some CPU time.  Amigas and
  511.          * other similarly broken software will need to waste
  512.          * the time, though.
  513.          */
  514. #ifndef unix
  515.         if (!f_sorted_names)
  516.             free(nlp);
  517. #endif
  518.     }
  519.     namelist = (struct name *)NULL;
  520.     namelast = (struct name *)NULL;
  521.  
  522.     if (f_sorted_names) {
  523.         while (0 != (p = name_next()))
  524.             fprintf(stderr, "tar: %s not found in archive\n", p);
  525.     }
  526. }
  527.